package org.itstep.stepup.webui.controllers;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.itstep.stepup.dal.entities.Project;
import org.itstep.stepup.dal.infrastructure.SessionFactoryUtil;
import org.itstep.stepup.dal.repositories.ProjectRepository;
import org.itstep.stepup.dal.repositories.impl.ProjectRepositoryImpl;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/project")
public class ProjectController {
	
	@InitBinder
	  public void initBinder(WebDataBinder binder) {
	    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
	    dateFormat.setLenient(false);
	    binder.registerCustomEditor(Date.class,
	        new CustomDateEditor(dateFormat, false));
	  }
	
	@RequestMapping(value = "/register", method = RequestMethod.GET)
	public String registerNewProject(ModelMap model) {
		Project project = new Project();
		
		model.addAttribute("PROJECT", project);
		
		return "project/register";
	}

	@RequestMapping(value = "/register", method = RequestMethod.POST)
	public Object registerNewProject(Project project, BindingResult result, ModelMap model) {		
		ProjectRepository repository = new ProjectRepositoryImpl(SessionFactoryUtil.getInstance());
		
		Map<String, Set<String>> valRules = validateProject(project);
		
		if(valRules.size() > 0){
			model.addAttribute("PROJECT", project);
			model.addAttribute("ValidationRules", valRules);
			
			return "project/register";
		}
		
		repository.insertProject(project);
		
		return "Project has been successfully registered";
	}
	
	@RequestMapping(value = "/isUnique", method = RequestMethod.POST)
	public @ResponseBody Object CheckProjectUniqueness(String name) {
		ProjectRepository repository = new ProjectRepositoryImpl(SessionFactoryUtil.getInstance());
		
		return repository.isProjectUnique(name).toString();
	}
	
	@RequestMapping(value = "/active", method = RequestMethod.GET)
	public String activeProjects(ModelMap model) {
		
		ProjectRepository repository = new ProjectRepositoryImpl(SessionFactoryUtil.getInstance());
		List<Project> projects = repository.getProjects();
		model.addAttribute("projects", projects);
		
		return "project/active-projects";
	}

	
//	@RequestMapping(value = "/register", method = RequestMethod.POST)
//	public String registerNewProject(ModelMap newProject) {		
//		ModelMap p = newProject;
//		return "Project has been successfully registered";
//	}
	
	private Map<String, Set<String>> validateProject(Project project) {
		Map<String, Set<String>> validationMessages = new HashMap<String, Set<String>>();
		
		// Project Name:
		//		- min length 5
		//		- max length 256
		//		- unique
		String projectName = project.getName();
		if (projectName == null || projectName.isEmpty()) {			
			addValidationMessage(validationMessages, "projectname", "Required field");
		} else { 
			projectName = projectName.trim();		
			if (projectName.length() < 5) {
				addValidationMessage(validationMessages, "projectname", "Length should not be less than 5");
			} else if (projectName.length() > 256) {
				addValidationMessage(validationMessages, "projectname", "Length should not be greater than 256");
			}
		}
		
		// Project Description
		//		- required
		//		- max length 4000
		String projectDescription = project.getDescription();
		if (projectDescription == null || projectDescription.isEmpty()) {
			addValidationMessage(validationMessages, "projectdescription", "Required field");
		} else { 
			projectDescription = projectDescription.trim(); 
			if (projectDescription.length() > 4000) {
				addValidationMessage(validationMessages, "projectdescription", "Length should not be greater than 4000");
			}
		}
		
		// Goal
		//		- required
		//		- max length 256
		String goal = project.getGoal();
		if (goal == null || goal.isEmpty()) {
			addValidationMessage(validationMessages, "goal", "Required field");
		} else {
			goal = goal.trim();
			if(goal.length() > 256){
				addValidationMessage(validationMessages, "goal", "Length should not be greater than 256");
			}
		}
		// Mission
		//		- required
		//		- max length 256
		
		String mission = project.getMission();
		if (mission == null || mission.isEmpty()) {
			addValidationMessage(validationMessages, "projectmission", "Required field");
		} else {
			mission = mission.trim();
			if(mission.length() > 256){
				addValidationMessage(validationMessages, "projectmission", "Length should not be greater than 256");
			}
		}
		
		// Photo
		//		- required
		//		- max file size 1MB
		
		byte[] fileData = project.getPhoto(); 
		
		if(fileData == null || fileData.length == 0) {
			addValidationMessage(validationMessages, "projectphoto", "File size should be correct");
		} else {
			if(fileData.length > 1048576) {
				addValidationMessage(validationMessages, "projectphoto", "File size should not be greater than 1 MB");
			}
		}
		
		// Video Link
		//		- required
		//		- max length 1024
		
		String videoLink = project.getVideoLink();

		if (videoLink == null || videoLink.isEmpty()) {
			addValidationMessage(validationMessages, "videolink", "Required field");
		} else {
			videoLink = videoLink.trim();
			if(videoLink.length() > 1024){
				addValidationMessage(validationMessages, "videolink", "Length should not be greater than 1024");
			}
		}
		
		// Expected budget
		//		- required
		//		- min value 10$
		//		- max value 100 000 000 000
		//		- numeric with 0-2 decimal digits
		
		BigDecimal expectedBudget  = project.getExpectedBudget();
		
		BigDecimal minRange = new BigDecimal("100");
		BigDecimal maxRange = new BigDecimal("100000000000");
		
		if(expectedBudget.compareTo(minRange) == -1 || expectedBudget.compareTo(maxRange) == 1){
			addValidationMessage(validationMessages, "budget", "Length should not be less than 100 and not greater than 100000000000");
		}
		
		// Expiration Date
		//		- required
		//		- date format
		//		- greater than now
		//		- max value now + 6 months
		
		Date expirationDate = project.getExpireDate();
		
		if(expirationDate == null){
			addValidationMessage(validationMessages, "expirationdate", "Date cannot empty");
		}
		
		Date today = new Date();
		
		if(expirationDate.before(today)){
			addValidationMessage(validationMessages, "expirationdate", "Expiration date must be later than now");
		}
		
		Date maxDate = addMonthsToDate(today, 6);
		
		if(expirationDate.after(maxDate)){
			addValidationMessage(validationMessages, "expirationdate", "Expiration date can not be later than now + 6 months");
		}
		
		return validationMessages;
	}
	
	private Date addMonthsToDate(Date date, int months){
		Date current = new Date();   
		Calendar cal = Calendar.getInstance();  
		cal.setTime(date);  
		cal.set(Calendar.MONTH, (cal.get(Calendar.MONTH) + months));  
		Date newDate = cal.getTime();  
		return newDate;
	}
	
	private void addValidationMessage(Map<String, Set<String>> validationMessages, String fieldName, String message) {
		if (!validationMessages.containsKey(fieldName)) {
			validationMessages.put(fieldName, new HashSet<String>());
		}
		Set<String> messages = validationMessages.get(fieldName);
		messages.add(message);		
	}
	
	

}